home *** CD-ROM | disk | FTP | other *** search
- ;; fracdelay.asm
- ;; Author - Rick Vander Kam
- ;; Copyright (c)1992 - All rights reserved
- ;; Modification history
- ;; --------------------
- ;; 02/01/92/rvk - initial file created from /usr/lib/dsp/ugsrc/delay.asm
- ;; no length-changing procedures, two FIR bins
- ;; 02/02/92/rvk - added length-changing procedures, reduced to one FIR bin,
- ;; added updates of bb0 and bb1 coeffs and end address arg
- ;;
- ;;
- ;;------------------------------ DOCUMENTATION ---------------------------
- ;; NAME
- ;; fracdelay (UG macro) - sample-based interpolated delay line using non-modulo indexing
- ;;
- ;; SYNOPSIS
- ;; fracdelay pf,ic,sout,aout0,sinp,ainp0,sdel,adel0,pdel0,edel0,afir0,bb00,bb10,chg0
- ;;
- ;; MACRO ARGUMENTS
- ;; pf = global label prefix (any text unique to invoking macro)
- ;; ic = instance count (s.t. pf\_fracdelay_\ic\_ is globally unique)
- ;; sout = output vector memory space ('x' or 'y')
- ;; aout0 = initial output vector memory address
- ;; sinp = input vector memory space ('x' or 'y')
- ;; ainp0 = initial input vector memory address
- ;; sdel = delay-line memory space ('x' or 'y')
- ;; adel0 = delay-line start address
- ;; pdel0 = delay-line pointer
- ;; edel0 = address of first sample beyond delay line
- ;; afir0 = address of undelayed sample in FIR filter
- ;; bb00 = coefficient of undelayed sample in FIR filter
- ;; bb10 = coefficient of once-delayed sample
- ;; chg0 = datum arg flag for changing length of delay line
- ;;
- ;; DSP MEMORY ARGUMENTS
- ;; Access Description Initialization
- ;; ------ ----------- --------------
- ;; x:(R_X)+ Output address aout0
- ;; x:(R_X)+ Input address ainp0
- ;; x:(R_X)+ FIR filter address afir0
- ;; x:(R_X)+ bb0 coefficient bb00
- ;; x:(R_X)+ Delay pointer pdel0
- ;; y:(R_Y)+ Start address adel0
- ;; y:(R_Y)+ change flag chg0
- ;; y:(R_Y)+ Last address + 1 edel0
- ;; y:(R_Y)+ bb1 coefficient bb10
- ;;
- ;; DESCRIPTION
- ;;
- ;; The fracdelay unit-generator implements an interpolated delay line which
- ;; can produce fractional-sample delays. It uses a circular
- ;; buffer (not modulo storage) followed by a two-point FIR filter. Therefore, this
- ;; UG does not result in a pure delay, but also affects the spectral characteristics
- ;; of the signal (the FIR filter is low-pass). It is well-suited for use in the
- ;; Karplus/Strong plucked-string model.
- ;;
- ;; For best performance, the input and output signals should be in the same
- ;; memory space, which should be different from the delay-line memory space.
- ;; I.e., if the delay table is in x memory, both input and output should be
- ;; in y memory, or vice versa.
- ;;
- ;; In pseudo-C notation:
- ;;
- ;; aout = x:(R_X)+;
- ;; ainp = x:(R_X)+;
- ;; afir = x:(R_X)+;
- ;; bb0= x:(R_X)+;
- ;; pdel = x:(R_X)+;
- ;; adel = y:(R_Y)+;
- ;; chg = y:(R_Y)+;
- ;; edel = y:(R_Y)+;
- ;; bb1 = y:(R_Y)+;
- ;;
- ;; for (n=0;n<I_NTICK;n++) {
- ;; sout:aout[n] = sdel:(afir)*bb0+(afir+1)*bb1;
- ;; sdel:(afir+1) = sdel:(afir);
- ;; sdel:(afir)=sdel:(pdel)
- ;; sdel:(pdel) = sinp:ainp[n];
- ;; if (++pdel>=edel) pdel=adel; plus other stuff to handle lengthening/shortening
- ;; }
- ;;
- ;; DSPWRAP ARGUMENT INFO
- ;; fracdelay (prefix)pf,(instance)ic, (dspace)sout,(output)aout, (dspace)sinp,(input)ainp,
- ;; (dspace)sdel,(address)adel,(address)pdel,(address)edel,(address)afir,
- ;; bb0,bb1,chg
- ;;
- ;;
- ;;
- ;; MAXIMUM EXECUTION TIME
- ;; ??? DSP clock cycles for one "tick" which equals 16 audio samples.
- ;;
- ;; MINIMUM EXECUTION TIME
- ;; ??? DSP clock cycles for one "tick".
- ;;
- ;; SOURCE
- ;; /user/rvk/ee265/test/fracdelay.asm
- ;;
- ;; ALU REGISTER USE
- ;; X0 = b0 coefficient
- ;; X1 = b1 coefficient
- ;; Y1 = start address of delay line
- ;; Y0 = last address of delay line
- ;; A = temporary register for input signal
- ;; B = temporary register for output signal
- ;;
- fracdelay macro pf,ic,sout,aout0,sinp,ainp0,sdel,adel0,pdel0,edel0,afir0,bb00,bb10,chg0
- new_xarg pf\_fracdelay_\ic\_,aout,aout0 ; output address arg
- new_xarg pf\_fracdelay_\ic\_,ainp,ainp0 ; input address arg
- new_xarg pf\_fracdelay_\ic\_,afir,afir0 ; filter address arg
- new_xarg pf\_fracdelay_\ic\_,bb0,bb00 ;
- new_xarg pf\_fracdelay_\ic\_,pdel,pdel0 ; current pointer arg
- new_yarg pf\_fracdelay_\ic\_,adel,adel0 ; start-address arg
- new_yarg pf\_fracdelay_\ic\_,chg,chg0 ;
- new_yarg pf\_fracdelay_\ic\_,edel,edel0 ; last-address+1 arg
- new_yarg pf\_fracdelay_\ic\_,bb1,bb10 ;
-
- move R_L,N_O ;safe keeping
- move x:(R_X)+,R_O ; output address to R_O
- move x:(R_X)+,R_I1 ; input address to R_I1
- move x:(R_X)+,R_L ;FIR address to R_L
- move x:(R_X)+,X0 y:(R_Y)+,Y1 ; bb0 to X0 (update), delay line start adr to Y1
- move y:(R_Y)+,N_I1 ;flag for changing delay line length
- move y:(R_Y)+,Y0 ; ad of end+1 to Y0 (update on exit)
- move y:(R_Y),X1 ;bb1 to X1 (update on exit)
- move x:(R_X),R_I2 ; delay ptr to R_I2 (update on exit)
-
- move R_I2,A ; current delay pointer expected in A
- do #I_NTICK,pf\_fracdelay_\ic\_tickloop
- cmp Y0,A ; check against last address + 1
- tge Y1,A ; wrap around if necessary
-
- jlt pf\_fracdelay_\ic\_notend
- clr B Y0,N_I2 ; 0 in B, save Y0
- move N_I1,Y0 ;chg flag to Y0
- cmp Y0,B ; check flag against 0
- btst #$F,Y0 ; check for pos or neg 16-bit number
- move N_I2,Y0 ;restore value
- jeq pf\_fracdelay_\ic\_notend ;no change if 0
- jcs pf\_fracdelay_\ic\_shrink ;flag <0 => check for shrinking
-
- ; Here to check for growing
- cmp X0,B ;check bb0 coeff
- jne pf\_fracdelay_\ic\_notend ;nonzero coeff => no change in length
- ;here only if growing
- move sinp:(R_I1)+,A ;new input to A
- move A,sdel:(R_I2)+ ;write new last cell
- move B,X1 ; clear bb1
- move R_I2,Y0 ; increase end addr by 1
- move sdel:(R_L),B ;new output sample to B
- move Y1,R_I2 ; addr of cell 1 in R_I2
- move B,sout:(R_O)+ ; ship output sample
- move #$7FFFFF,X0 ;set bb0 to 1
- move X0,x:-(R_X) ;update bb0
- move Y0,y:-(R_Y) ;update delay line end addr
- move x:(R_X)+,X0 y:(R_Y)+,Y0 ;dummy reads
- jmp pf\_fracdelay_\ic\_niter ;go to next iteration
-
- pf\_fracdelay_\ic\_shrink
- ;Here to check for shrinking
- cmp X1,B
- jne pf\_fracdelay_\ic\_notend ;no change if bb1 != 0
- ;here only if shrinking
- move R_X,N_X ;save
- move Y1,R_X ;cell 1 addr to R_X
- move sdel:-(R_I2),A ;recover last input
- move B,X0 ; clr bb0
- move sdel:(R_X),B ;new output to B
- if "sdel"!="sout" ;ship output, last input to cell 1
- move B,sout:(R_O)+ A,sdel:(R_X)+
- else
- move A,sdel:(R_X)+
- move B,sout:(R_O)+
- endif
- move #$7FFFFF,X1 ;set bb1 to 1
- move sdel:(R_X),A ;cell 2 to A
- move R_I2,Y0 ; new end addr to Y0
- move sinp:(R_I1)+,B ;new input to B
- move B,sdel:(R_X)+ ;new input to cell 2
- move A,sdel:(R_L) ;old cell 2 to undel bin
- move R_X,R_I2 ;cell 3 addr to R_I2 (to A below)
- move N_X,R_X ;restore
- move Y0,y:-(R_Y) ;update delay line end addr
- move X0,x:-(R_X) ;update bb0
- move x:(R_X)+,X0 y:(R_Y)+,Y0 ;dummy reads
- jmp pf\_fracdelay_\ic\_niter ;go to next iteration
-
- pf\_fracdelay_\ic\_notend
- move A,R_I2 ; delay pointer for next entry
- move Y0,N_I2 ;clear out Y0
-
- ; load current input to A, current delay value to B
- if "sinp"=="sdel"
- move sinp:(R_I1)+,A ;
- move sdel:(R_I2),B ; no post-increment!
- else
- move sdel:(R_I2),B sinp:(R_I1)+,A
- endif
-
- ; output current delay-line value, overwrite with input (general case)
- move sdel:(R_L),Y0 ;prev undelayed samp to Y0
- move A,sdel:(R_I2)+ ;new sample is written
- mpy X1,Y0,A ;b1*(once-delayed)
- move B,Y0 ; current del line value to Y0 as undelayed
- mac X0,Y0,A Y0,sdel:(R_L) ;output sample is in A, new undel to its bin
- move A,sout:(R_O)+ ;ship the output
- move N_I2,Y0 ;restore end address value
- pf\_fracdelay_\ic\_niter
- move R_I2,A ; delay pointer for next entry
- pf\_fracdelay_\ic\_tickloop
- move N_O,R_L ; restore R_L
- move A,x:(R_X)+ ; save delay pointer for next entry
- move X1,y:(R_Y)+ ;update bb1
- endm
-
-
-